package com.thread.threadfirst.SpringThreadPool;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 自定义线程池可以在启动类中、新建一个类、实现了AsyncConfigurer Interface接口的实现类中进行配置。
 * <p>
 * 实现AsyncConfigurer接口对异常线程池更加细粒度的控制
 * a) 自定义线程池
 * b) 对void方法抛出的异常自动处理的类AsyncUncaughtExceptionHandler
 * <p>
 * 其实对void方法抛出的异常进行处理也可以直接在那个异常方法中catch exception，而这个类中的异常自动处理类AsyncUncaughtExceptionHandler 是个更细腻的异常处理，会显示异常方法的方法名、参数、抛出的异常信息。
 * 所以需要详细细腻的数据时，可以使用这个类来对void方法抛出的异常自动处理，但是不能使用在对返回值是Future的方法的异常处理，所以有些鸡肋。应该使用场景不多。
 */
//@Component
public class MyAsyncConfigurer implements AsyncConfigurer {
    private static final Logger logger = LoggerFactory.getLogger(MyAsyncConfigurer.class);

    /**
     * 自定义异常线程池
     * 有此线程池就可以注释掉启动类中的自定义线程池了，如果不想注释掉 那么这里必须也得像启动类中的线程池一样有@Bean注解。
     *
     * @return
     */
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(1);
        //配置最大线程数
        executor.setMaxPoolSize(1);
        //配置队列大小
        executor.setQueueCapacity(1);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("MyAsync-");
        //true 在关机时等待任务完成,false 不等待，此参数和下面的setAwaitTerminationSeconds是优雅的停机所需的配置
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //等待的时间，因为不能无限的等待下去。
        executor.setAwaitTerminationSeconds(60 * 15);
        // rejection-policy：当pool已经达到max size、queue也满了的时候，如何处理新任务
        // CALLER_RUNS：不在新线程中执行任务，而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }

    /**
     * 自定义异常处理类
     *
     * @return
     */
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        //匿名内部类
        return new AsyncUncaughtExceptionHandler() {
            @Override
            public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
                logger.info("Exception message - " + throwable.getMessage());
                logger.info("Method name - " + method.getName());
                for (Object param : objects) {
                    logger.info("Parameter value - " + param);
                }
            }
        };
    }
}
